package com.wuage.application.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wuage.application.IUacAccountService;
import com.wuage.application.IUacPermissionService;
import com.wuage.application.IUacRoleService;
import com.wuage.application.IUacTenantService;
import com.wuage.domain.mapper.UacAccountMapper;
import com.wuage.domain.model.UacAccount;
import com.wuage.domain.model.UacPermission;
import com.wuage.domain.model.UacRole;
import com.wuage.domain.model.UacTenant;
import com.wuage.infrastructure.exception.BizException;
import com.wuage.infrastructure.status.BizResultCode;
import com.wuage.infrastructure.status.RoleEnum;
import com.wuage.infrastructure.utils.BeanUtils;
import com.wuage.infrastructure.utils.GeneratorUtils;
import com.wuage.infrastructure.utils.JwtUtils;
import com.wuage.interfaces.account.domain.AccountRegisterDO;
import com.wuage.interfaces.account.domain.AccountQueryDO;
import com.wuage.interfaces.account.domain.AdminSaveOrUpdateAccountDO;
import com.wuage.interfaces.account.domain.RegisterAdminDO;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * @author Shynin
 * @version 1.0
 * @date 2020-09-03 09:37
 */
@Service
public class UacAccountServiceImpl extends ServiceImpl<UacAccountMapper, UacAccount> implements IUacAccountService {

    @Resource
    private UacAccountMapper accountMapper;

    @Resource
    private IUacTenantService uacTenantService;

    @Resource
    private IUacRoleService uacRoleService;

    @Resource
    private IUacPermissionService uacPermissionService;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public IPage<UacAccount> getUsersByPage(AccountQueryDO accountQueryDO) {
        return this.lambdaQuery()
                .notIn(UacAccount::getRole, RoleEnum.ADMIN.getRoleCode(), RoleEnum.SUPER_ADMIN.getRoleCode())
                .eq(UacAccount::getTenantId, JwtUtils.getLoginUser().getTenantId())
                .and(!StringUtils.isEmpty(accountQueryDO.getUsername()), wrapper -> wrapper.like(UacAccount::getUsername, "%" + accountQueryDO.getUsername() + "%").or().like(UacAccount::getEmail, "%" + accountQueryDO.getUsername() + "%"))
                .page(new Page<>(accountQueryDO.getCurrent(), accountQueryDO.getSize()));
    }

    @Override
    public UacAccount getUserByUsername(String username) {
        QueryWrapper<UacAccount> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return accountMapper.selectOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AccountRegisterDO accountRegisterDO) {
        QueryWrapper<UacAccount> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", accountRegisterDO.getUsername());
        UacAccount uacAccount = accountMapper.selectOne(queryWrapper);
        if(!Objects.isNull(uacAccount)) {
            throw BizResultCode.USER_EXISTS.toException();
        } else {
            Long id = GeneratorUtils.generateRandomId();
            uacAccount = new UacAccount();
            uacAccount.setId(id);
            uacAccount.setPassword(bCryptPasswordEncoder.encode(accountRegisterDO.getPassword()));
            uacAccount.setUsername(accountRegisterDO.getUsername());
            uacAccount.setRole(RoleEnum.CUSTOMER.getRoleCode());
            accountMapper.insert(uacAccount);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean enableAccount(Long id) {
        UacAccount uacAccount = accountMapper.selectById(id);
        if(Objects.isNull(uacAccount)) {
            throw new BizException(BizResultCode.USER_NOT_EXISTS);
        }
        UpdateWrapper<UacAccount> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("enable", !uacAccount.getEnable());
        return accountMapper.update(null, updateWrapper) > 0;
    }

    @Override
    public String resetPassword(Long id) {
        UacAccount uacAccount = accountMapper.selectById(id);
        if(Objects.isNull(uacAccount)) {
            throw new BizException(BizResultCode.USER_NOT_EXISTS);
        }
        String password = GeneratorUtils.generateCode(6);
        uacAccount.setPassword(bCryptPasswordEncoder.encode(password));
        // todo 管理员重置密码后发送验证码到用户手机上
        accountMapper.updateById(uacAccount);
        return password;
    }

    @Override
    public Boolean resetPassword(Long id, String password) {
        UacAccount uacAccount = accountMapper.selectById(id);
        if(Objects.isNull(uacAccount)) {
            throw new BizException(BizResultCode.USER_NOT_EXISTS);
        }
        uacAccount.setPassword(bCryptPasswordEncoder.encode(password));
        accountMapper.updateById(uacAccount);
        return true;
    }

    @Override
    public List<UacAccount> getAdmins() {
        return this.lambdaQuery().eq(UacAccount::getRole, RoleEnum.ADMIN.getRoleCode()).list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addAdmin(RegisterAdminDO registerAdminDO) {
        if(Objects.nonNull(getUserByUsername(registerAdminDO.getUsername()))) {
            throw BizResultCode.USER_EXISTS.toException();
        }
        // 先创建租户
        UacTenant uacTenant = uacTenantService.create(registerAdminDO.getTenantName());

        // 再创建用户，并且绑定租户
        UacAccount uacAccount = BeanUtils.copyProperties(registerAdminDO, UacAccount.class);
        uacAccount.setPassword(bCryptPasswordEncoder.encode(uacAccount.getPassword()));
        uacAccount.setTenantId(uacTenant.getId());
        uacAccount.setRole(RoleEnum.ADMIN.getRoleCode());
        this.save(uacAccount);

        // 创建角色，并且绑定角色
        UacRole uacRole = uacRoleService.createAdmin(uacTenant);

        // 给这个管理员角色初始化系统菜单
        List<UacPermission> uacPermissions = uacPermissionService.createAdminPermission(uacRole);
        return true;
    }

    @Override
    public UacAccount saveOrUpdateAccount(AdminSaveOrUpdateAccountDO adminAddAccountDO) {
        // 查询租户
        UacTenant uacTenant = uacTenantService.getById(JwtUtils.getLoginUser().getTenantId());
        // 查询角色
        UacRole uacRole = uacRoleService.getByRoleAndTenant(adminAddAccountDO.getRole(), uacTenant.getId());
        if(Objects.isNull(uacRole)) {
            throw BizResultCode.ROLE_ERROR.toException();
        }
        // 创建用户
        UacAccount uacAccount = BeanUtils.copyProperties(adminAddAccountDO, UacAccount.class);
        uacAccount.setPassword(bCryptPasswordEncoder.encode(uacAccount.getPassword()));
        uacAccount.setTenantId(uacTenant.getId());
        uacAccount.setTenantName(uacTenant.getName());
        this.saveOrUpdate(uacAccount);
        return uacAccount;
    }

    @Override
    public UacAccount getById(Long id) {
        return accountMapper.selectById(id);
    }

    @Override
    public Boolean bindEmail(Long id, String email) {
        UacAccount account = accountMapper.selectById(id);
        if(Objects.isNull(account)) {
            throw new BizException(BizResultCode.USER_NOT_EXISTS);
        }
        if(account.getEmailAuthentication()) {
            throw new BizException(BizResultCode.EMAIL_CHECKED);
        }
        account.setEmailAuthentication(true);
        account.setEmail(email);
        accountMapper.updateById(account);
        return true;
    }
}
